package com.xc.stock.aop.distributedlock;

import java.lang.reflect.Method;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.xc.stock.aop.annotation.DistributedLocks;

@Aspect
@Component
public class DistributedLocksAspect {


	@Autowired(required = false)
	private DistributedLockTemplate lockTemplate;

	@Pointcut("@annotation(com.xc.stock.aop.annotation.DistributedLocks)")
	public void distributedLocksAspect() {
	}

	@Around(value = "distributedLocksAspect()")
	public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
		MethodSignature ms = ((MethodSignature) pjp.getSignature());
		Method method = ms.getMethod();
		DistributedLockCallback<Object> callback = new DistributedLockCallback<Object>() {
			@Override
			public Object process() {
				return proceed(pjp);
			}
		};
		
		return lockTemplate.lock(callback, DistributedLockInfo.build(method.getAnnotation(DistributedLocks.class), pjp.getArgs()));
	}

	@AfterThrowing(value = "distributedLocksAspect()", throwing = "ex")
	public void afterThrowing(Throwable ex) {
		throw new RuntimeException(ex);
	}

	public Object proceed(ProceedingJoinPoint pjp) {
		try {
			return pjp.proceed();
		} catch (Throwable throwable) {
			if(throwable instanceof RuntimeException) {
				throw ((RuntimeException) throwable);
			}
			throw new RuntimeException(throwable);
		}
	}

}
